package com.rowling.factory;

import com.google.auto.service.AutoService;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@AutoService(Processor.class)
@SupportedAnnotationTypes("com.rowling.factory.Factory")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class FactoryAnnoProcessor extends AbstractProcessor {

    private Types typeUtils;    //工具，处理类型的工具
    private Elements elementUtils; //所有的元素，处理元素，代表源代码的一些东西，如注解，包
    private Filer filer;        //所有的文件，创建文件
    private Messager messager;  //需要用到的Messager,警告，错误，异常提示，使用这个

    private Map<String,FactoryGroupedClasses> factoryGroupedClassesMap  = new HashMap<>();//所有加了注解的


    /**
     * 初始化，有哪些个文件，以及文件中的类型是的什么，以及文件中的元素是什么
     * 还有出现问题的时候，使用注解解析器，进行打印操作
     * @param processingEnv
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        typeUtils = processingEnv.getTypeUtils();
        elementUtils = processingEnv.getElementUtils();
        filer = processingEnv.getFiler();
        messager = processingEnv.getMessager();
    }


    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        try {
            //遍历所有加了@Factory注解的元素
            for(Element annotatedElement : roundEnv.getElementsAnnotatedWith(Factory.class)){
                //检查元素是不是加在Class上
                if(annotatedElement.getKind() != ElementKind.CLASS){
                    throw new ProcessorException(annotatedElement,"Only class can annotated with @%s", Factory.class.getSimpleName());
                }
                //类类型的注解
                TypeElement typeElement =(TypeElement) annotatedElement;
                //封装注解为注解类，为了以后让它生成一个class文件，可以获取全类名，类名 。执行后就有了Class
                FactoryAnnotatedClass annotationClass = new FactoryAnnotatedClass(typeElement);
                //下面的代码含义：把所有加了@Factory的类进行一个包装，包装成一个group
                //factoryGroupedClassesMap<@Factory,Map<"Mile",FactoryAnnotatedClass>>
                FactoryGroupedClasses factoryGroupedClasses = factoryGroupedClassesMap.get(annotationClass.getQualifiedFactoryGroupName());
                //如果没有的话，组成双层map
                if (factoryGroupedClasses ==null){
                    String qualifiedFactoryGroupName = annotationClass.getQualifiedFactoryGroupName();//获取到全组名
                    System.out.println("qualifiedFactoryGroupName:"+qualifiedFactoryGroupName);
                    factoryGroupedClasses = new FactoryGroupedClasses(qualifiedFactoryGroupName);
                    factoryGroupedClassesMap.put(qualifiedFactoryGroupName, factoryGroupedClasses);
                }
                //把所有加了@Factory 封装成 factoryGroupedClassesMap<@Factory,Map<"Mile",FactoryAnnotatedClass>>
                factoryGroupedClasses.add(annotationClass);
                //类中生成代码
                factoryGroupedClasses.generateCode(elementUtils,filer);
                factoryGroupedClassesMap.clear();


            }
        }catch (ProcessorException e){
            error(e.getElement(),e.getMessage());
        }
        catch (IOException e) {
            error(null,e.getMessage());//不是元素导致的异常
        }


        return false;
    }

    public void error(Element element,String msg){
        messager.printMessage(Diagnostic.Kind.ERROR,msg,element);
    }
}
